package cn.lg.soar.general.service;

import cn.lg.soar.common.algorithm.CryptoUtils;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.ParameterUtil;
import cn.lg.soar.common.util.current.UserContext;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.general.api.enums.ThumbnailSizeEnum;
import cn.lg.soar.general.entity.FileMetadata;
import cn.lg.soar.general.manager.FileTemplateManager;
import cn.lg.soar.general.s3.FileTemplate;
import com.amazonaws.services.s3.model.S3Object;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/6/1 13:17
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class FileAccessService {

    @Value("${lg.general.upload.secret:SntoNIroCEMHEYPBqWyUhJV0n4rzeNTS}")
    private String secret;

    @Autowired
    private IFileMetadataService fileMetadataService;
    @Autowired
    private FileTemplateManager uploadTemplateManager;

    private String signTemporaryUrl(String bucketName, String fileInfo) {
        return CryptoUtils.sm3Str((bucketName +"/"+ secret +"/"+ fileInfo).getBytes());
    }

    /**
     * 创建临时访问路径
     * @param anonymous 是否可以匿名访问
     * @param fileId 文件id
     * @param expire 有效期
     * @param userIds 指定用户可访问，不指定则任意用户可访问
     * @return
     */
    public String createTemporaryUrl(boolean anonymous, long fileId, long expire, Set<Long> userIds) {
        if (anonymous) {
            AssertUtil.isTrue(DataUtil.isEmpty(userIds), "匿名访问不可指定 userIds");
        }
        FileMetadata fileMetadata = fileMetadataService.getById(fileId);
        AssertUtil.notNull(fileMetadata, "文件不存在");
        // 匿名的不能设置用户权限
        Set<Long> set = userIds == null ? Collections.emptySet() : userIds;
        long[] longs = new long[set.size() + 4];
        longs[0] = System.currentTimeMillis() + expire;
        longs[1] = fileMetadata.getStorageId();
        longs[2] = fileId;
        longs[3] = UserContext.getUserId();
        int i = 4;
        for (Long id : set) {
            longs[i++] = id;
        }
        String bucketName = fileMetadata.getBucketName();
        String idsStr = DataUtil.longsToBase64(longs);
        String fileInfo = idsStr +"."+ fileMetadata.getSuffix();
        String sign = signTemporaryUrl(bucketName, fileInfo);
        return String.format("%s/%s/%s/%s", anonymous ? "anon" : "auth", sign, bucketName, fileInfo);
    }

    /**
     * 创建临时访问路径
     * @param anonymous 是否可以匿名访问
     * @param fileId 文件id
     * @param expire 有效期
     * @param userIds 指定用户可访问，不指定则任意用户可访问
     * @return
     */
    public String createTemporaryUrl(boolean anonymous, long fileId, long expire, Long...userIds) {
        return createTemporaryUrl(anonymous, fileId, expire, Arrays.stream(userIds).filter(Objects::nonNull).collect(Collectors.toSet()));
    }

    public S3Object temporaryUrlAccess(String sign, String bucketName, String fileInfo, ThumbnailSizeEnum size) {
        String[] split = fileInfo.split("\\.");
        ParameterUtil.isTrue(split.length == 2, "链接格式错误");
        long[] longs = DataUtil.base64ToLongs(split[0]);
        ParameterUtil.isTrue(longs.length >= 4, "链接格式错误");
        // 验证有效期
        ParameterUtil.isTrue(longs[0] > System.currentTimeMillis(), "链接已失效");
        // 验证签名
        ParameterUtil.isTrue(signTemporaryUrl(bucketName, fileInfo).equals(sign), "链接无效");
        if (longs.length > 4) {
            // 验证授权
            boolean flag = false;
            long userId = UserContext.getUserId();
            for (int i = 4; i < longs.length; i++) {
                if (userId == longs[i]) {
                    flag = true;
                    break;
                }
            }
            AssertUtil.isTrue(flag, "您无权限访问该文件");
        }
        // 访问文件
        FileTemplate uploadTemplate = uploadTemplateManager.getTemplate(longs[1]);
        return uploadTemplate.getObject(bucketName, longs[2] +"."+ split[1], size);
    }

    /**
     * 创建永久访问路径
     * @param metadata
     * @return
     */
    public String createFixedSecretUrl(FileMetadata metadata) {
        return String.format(
                "fixed/%s/%s",
                metadata.getSecret(),
                metadata.getId()
        );
    }

    /**
     * 创建永久访问路径
     * @param fileId
     * @return
     */
    public String createFixedSecretUrl(long fileId) {
        return createFixedSecretUrl(fileMetadataService.getById(fileId));
    }

    public S3Object fixedSecretAccess(String secret, long fileId, ThumbnailSizeEnum size) {
        FileMetadata metadata = fileMetadataService.getById(fileId);
        AssertUtil.notNull(metadata, "链接无效");
        AssertUtil.isTrue(secret.equals(metadata.getSecret()), "链接无效");
        FileTemplate uploadTemplate = uploadTemplateManager.getTemplate(metadata.getStorageId());
        return uploadTemplate.getObject(metadata.getBucketName(), metadata.filename(), size);
    }

}
